﻿using MSSClient.OCR;
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using ZBar;
using ZXing;

namespace MSSClient.Utils
{
    //OCR识别工具类
    class QRDecodeUtil
    {
        public static string QRCodePath { get; private set; }
        public static Boolean IsDebug = true;//debug模式，输出处理的图像,true-启用，false-不启用
        public static Boolean OutPutQrCodeTag = false;
        /// <summary>
        /// openCV处理识别图像中是否含有发票抬头，逻辑：识别提取图像中的矩形区域，
        /// 按照规定的比例范围来判断是否存在发票抬头
        /// </summary>
        /// <param name="path">图像路径</param>
        /// <returns></returns>
        public static bool DetectInvoiceHeadImage(Mat textImageSrc,String path, string dic ,Boolean isDebug)
        {
            #region
            IsDebug = isDebug;
            Bitmap bitmap = new Bitmap(path);
            int DpiTag = CommonUtil.DeCodeDpiFromBitmap(bitmap);
            if (IsDebug)
            {
                Console.WriteLine("");
                Console.WriteLine("长：" + bitmap.Height + ",宽：" + bitmap.Width + ",dpi为：" + DpiTag);
                if (!Directory.Exists("E:\\OenpCVImage\\" + dic))//判断文件夹是否存在 
                    Directory.CreateDirectory("E:\\OenpCVImage\\" + dic);//不存在则创建文件夹 
            }

            //1.转化成灰度图
            //Bitmap testBitmap2 = MatToBitmap(textImageSrc);
            //testBitmap2.Save("E:\\qrcode223.jpg");
            Mat gray = PositionArea.WipeOffBuleOrRedArea(false,path);

            //Bitmap testBitmap = MatToBitmap(gray);
            //testBitmap.Save("E:\\qrcode22.jpg");
            //2.形态学变换的预处理，得到可以查找矩形的轮廓
            string fileFrontName = DateTime.Now.ToString("yyyyMMddHHmmssf");
            Mat dilation = PreprocessFindInvoiceHead(gray, dic, fileFrontName, DpiTag);

            //3.查找和筛选文字区域
            IList<RotatedRect> rects = FindInvoiceTagRegion(dilation);
            if (IsDebug)
            {
                //用绿线画出这些找到的轮廓
                Scalar scalar = new Scalar(0, 255, 0);
                foreach (RotatedRect rect in rects)
                {
                    Point2f[] P;
                    P = rect.Points();
                    for (int j = 0; j <= 3; j++)
                        Cv2.Line(textImageSrc, P[j], P[(j + 1) % 4], scalar, 2);
                }
                //textImageSrc.SaveImage("E:\\OenpCVImage\\" + dic + "\\" + fileFrontName + "_8-发票抬头标识图.jpg");
                textImageSrc.SaveImage("E:\\OenpCVImage\\" + fileFrontName + "_8-发票抬头标识图.jpg");
            }
            if (rects.Count == 0)
                return false;
            else
                return true;
            #endregion
        }

        /// <summary>
        /// 查找/识别二维码
        /// </summary>
        /// <param name="path">原图路径</param>
        /// <param name="dic">缓存文件夹</param>
        /// <returns></returns>
        public static List<String> DetectImageQrCode(Mat textImageSrc,String path, string dic,Boolean isDebug)
        {
            #region
            IsDebug = isDebug;
            Mat gray = new Mat();
            Bitmap bitmap = new Bitmap(path);
            string fileFrontName = DateTime.Now.ToString("yyyyMMddHHmmssf");
            int dpiType = CommonUtil.DeCodeDpiFromBitmap(bitmap);
            List<String> qrCodeInfo = new List<string>();
            if (IsDebug)
            {
                if (!Directory.Exists("E:\\OenpCVImage\\" + dic))//判断文件夹是否存在 
                    Directory.CreateDirectory("E:\\OenpCVImage\\" + dic);//不存在则创建文件夹 
            }
            //第一次尝试识别 -- 二值化，膨胀，腐蚀处理
            gray = PositionArea.WipeOffBuleOrRedArea(true, path);//先去除红色的内容
            //Cv2.CvtColor(textImageSrc, gray, ColorConversionCodes.RGB2GRAY);
            Mat dilationQrCodeArea = PreprocessQrCode(gray, dic, fileFrontName, dpiType, false);
            List<RotatedRect> rects = FindQrCodeRegion(dilationQrCodeArea, dpiType);
            
            if (rects.Count == 0) qrCodeInfo.Add("noCheck");
            else qrCodeInfo.Add("Check");

            String qrCodeStr = ReadQrCode(rects,bitmap, fileFrontName, textImageSrc);
            bitmap.Dispose();
            //第二次尝试识别 -- 分离通道，保留蓝色区域
            //if (qrCodeStr == "0")
            //{
            //Mat dilationQrCodeArea2 = GetBlueAreaQrCode(path, dpiType, dic, fileFrontName);
            //rects = FindQrCodeRegion(dilationQrCodeArea2,dpiType);
            //String qrCodeStr2 = ReadQrCode(rects, bitmap, fileFrontName + "-2", textImageSrc);
            //if (qrCodeStr2 != "0")
            //    qrCodeInfo.Add(qrCodeStr2);
            //}
            //else
            if (!qrCodeStr.Equals("0"))
            {
                qrCodeInfo.Add(qrCodeStr);
            }
            

            if (IsDebug) ;
                //textImageSrc.SaveImage("E:\\OenpCVImage\\" + dic + "\\" + fileFrontName + "_8-二维码标识图.jpg");

            return qrCodeInfo;
            #endregion
        }

        /// <summary>
        /// 只保留蓝色的区域，去除其他颜色的区域，使二维码区域整洁
        /// </summary>
        /// <param name="path">图像路径</param>
        /// <param name="dpiType">dpi</param>
        /// <param name="dic">缓存路径文件夹</param>
        /// <param name="filePath">缓存路径</param>
        /// <returns></returns>
        public static Mat GetBlueAreaQrCode(String path ,int dpiType,string dic,string filePath)
        {
            #region
            Mat imgHSV = new Mat();
            Mat textImageSrc = Cv2.ImRead(path);
            Mat elementBFErode = OcrUtil.elementBFByDpi(dpiType, 1);
            Mat elementBFDilate = OcrUtil.elementBFByDpi(dpiType, 2);
            Cv2.CvtColor(textImageSrc, imgHSV, ColorConversionCodes.BGR2HLS);
            int iLowH = 100;
            int iHighH = 140;

            int iLowS = 90;
            int iHighS = 255;

            int iLowV = 10;
            int iHighV = 255;

            Scalar low_range = new Scalar(0, 123, 100);
            Scalar high_range = new Scalar(5, 255, 255);

            Mat[] hsvSplit;
            Cv2.Split(imgHSV, out hsvSplit);

            Cv2.EqualizeHist(hsvSplit[2], hsvSplit[2]);
            Cv2.Merge(hsvSplit, imgHSV);
            Mat imgThresholded = new Mat();

            Cv2.InRange(imgHSV, new Scalar(iLowH, iLowS, iLowV), new Scalar(iHighH, iHighS, iHighV), imgThresholded); //Threshold the image
            if (IsDebug)
                Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\QR2_" + filePath + "_去色彩-原图.jpg", imgThresholded);
                
            //开操作(去除一些噪点)
            Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(5, 5));
            Cv2.MorphologyEx(imgThresholded, imgThresholded, MorphTypes.Open, element);

            //闭操作(连接一些连通域)
            Cv2.MorphologyEx(imgThresholded, imgThresholded, MorphTypes.Close, element);
            if (IsDebug)
                Cv2.ImWrite("E:\\OenpCVImage\\"+dic+ "\\QR2_" + filePath + "_去色彩-开闭运算.jpg", imgThresholded);
            //腐蚀一次，去掉细节
            Mat erodeMat = new Mat();
            Cv2.Erode(imgThresholded, erodeMat, elementBFErode);
            if (IsDebug) {
                Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\QR2_" + filePath + "_去色彩-腐蚀1.jpg", erodeMat);
                Cv2.Erode(erodeMat, erodeMat, elementBFErode);
                Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\QR2_" + filePath + "_去色彩-腐蚀2.jpg", erodeMat);
            }
            //膨胀一次，让轮廓突出
            Mat dilateMat = new Mat();
            Cv2.Dilate(erodeMat, dilateMat, elementBFDilate);
            if (IsDebug)
                Cv2.ImWrite("E:\\OenpCVImage\\" +dic+ "\\QR2_" + filePath + "_去色彩-膨胀1.jpg", dilateMat);
            Cv2.Dilate(dilateMat, dilateMat, elementBFDilate);
            if (IsDebug)
                Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\QR2_" + filePath + "_去色彩-膨胀2.jpg", dilateMat);

            return dilateMat;
            #endregion
        }

        /// <summary>
        /// 形态学变换的预处理，得到可以查找发票抬头矩形的轮廓
        /// </summary>
        /// <param name="gray"></param>
        /// <returns></returns>
        public static Mat PreprocessFindInvoiceHead(Mat gray, string dic, string fileFrontName, int dpi)
        {
            #region
            //Sobel算子，x方向求梯度
            Mat matX = new Mat();
            Mat elementBFErode = new Mat();
            Mat elementBFDilate = new Mat();
            //膨胀和腐蚀操作核参数设定
            //控制高度设置可以控制上下行的膨胀程度，例如3比4的区分能力更强,但也会造成漏检
            elementBFErode = OcrUtil.elementBFByDpi(dpi, 1);
            elementBFDilate = OcrUtil.elementBFByDpi(dpi, 2);

            Cv2.Sobel(gray, matX, MatType.CV_8U, 1, 0, 3, 3, 1, 0);
            //Sobel算子，y方向求梯度
            Mat matY = new Mat();
            Cv2.Sobel(gray, matY, MatType.CV_8U, 0, 1, 3, 3, 1, 0);
            Mat gradXY = new Mat();
            Cv2.Add(matX, matY, gradXY);//XY梯度相加
            if (IsDebug)
                Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\" + fileFrontName + "_1-XY梯度.jpg", gradXY);

            //模糊 平均模糊
            OpenCvSharp.Size blurSize = OcrUtil.BlurMatSizeByDpi(dpi);
            Mat blurMat = new Mat();
            Cv2.Blur(gradXY, blurMat, blurSize);
            if (IsDebug)
                Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\" + fileFrontName + "_2-模糊[平均模糊].jpg", blurMat);

            //二值化
            Mat thresholdMat = new Mat();

            Cv2.Threshold(blurMat, thresholdMat, 0, 255, ThresholdTypes.Otsu);
            if (IsDebug)
                Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\" + fileFrontName + "_3-二值化.jpg", thresholdMat);

            ////开运算
            //Mat morphologyExMat = new Mat();
            //Mat element = Cv2.GetStructuringElement(MorphShapes.Cross, new OpenCvSharp.Size(10, 10));
            //Cv2.MorphologyEx(thresholdMat, morphologyExMat, MorphTypes.Open, element);
            //Cv2.ImWrite("4-开运算.jpg", morphologyExMat);

            //腐蚀一次，去掉细节，表格线等。这里去掉的是竖直的线
            //Mat erodeMat = new Mat();
            //Cv2.Erode(thresholdMat, erodeMat, elementBFErode);
            //Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\" + fileFrontName + "_5-腐蚀1.jpg", erodeMat);

            //Cv2.Erode(erodeMat, erodeMat, elementBF);
            //Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\" + fileFrontName + "_5-腐蚀2.jpg", erodeMat);

            //膨胀一次，让轮廓突出
            Mat dilateMat = new Mat();
            Cv2.Dilate(thresholdMat, dilateMat, elementBFDilate);
            if (IsDebug)
                Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\" + fileFrontName + "_6-膨胀1.jpg", dilateMat);

            //再膨胀一次，让轮廓突出
            //Mat dilateMat2 = new Mat();
            //Cv2.Dilate(dilateMat, dilateMat2, elementBFDilate);
            //Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\" + fileFrontName + "_6-膨胀2.jpg", dilateMat2);

            //Cv2.Dilate(dilateMat, dilateMat2, elementBF);
            //Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\" + fileFrontName + "_6-膨胀3.jpg", dilateMat2);

            //查找边缘
            Cv2.Canny(dilateMat, dilateMat, 75, 150, 7, true);
            if (IsDebug)
                Cv2.ImWrite("E:\\OenpCVImage\\" + dic +"\\"+ fileFrontName +"_7-查找边缘.jpg", dilateMat);
            CommonUtil.ClearMemory();
            return dilateMat;
            #endregion
        }

        /// <summary>
        /// 形态学变换的预处理，查询定位二维码
        /// </summary>
        /// <param name="gray"></param>
        /// <param name="dic"></param>
        /// <param name="fileFrontName"></param>
        /// <param name="dpiType">dpi类型</param>
        /// <param name="secondsTag">第二次执行，用于处理二维码与发票线框太近</param>
        /// <returns></returns>
        public static Mat PreprocessQrCode(Mat gray, string dic, string fileFrontName, int dpiType, bool secondsTag)
        {
            #region
            //Mat thresholdMat1 = new Mat();
            //Cv2.Threshold(gray, thresholdMat1, 0, 255, ThresholdTypes.Otsu);
            //Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\" + fileFrontName + "二维码单独-二值化.jpg", thresholdMat1);
            //Sobel算子，x方向求梯度
            Mat matX = new Mat();
            //膨胀和腐蚀操作核参数设定
            //控制高度设置可以控制上下行的膨胀程度，例如3比4的区分能力更强,但也会造成漏检
            Mat elementBFErode = new Mat();
            Mat elementBFDilate = new Mat();
            elementBFErode = OcrUtil.elementBFByDpi(dpiType, 1);
            elementBFDilate = OcrUtil.elementBFByDpi(dpiType, 2);
            Cv2.Sobel(gray, matX, MatType.CV_8U, 1, 0, 3, 3, 1, 0);

            //Sobel算子，y方向求梯度
            Mat matY = new Mat();
            Cv2.Sobel(gray, matY, MatType.CV_8U, 0, 1, 3, 3, 1, 0);
            Mat gradXY = new Mat();
            Cv2.Add(matX, matY, gradXY);//XY梯度相加
            if (IsDebug)
                Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\QR_" + fileFrontName + "_1-XY梯度.jpg", gradXY);

            //模糊 平均模糊
            OpenCvSharp.Size blurSize =OcrUtil.BlurMatSizeByDpi(dpiType);
            Mat blurMat = new Mat();
            Cv2.Blur(gradXY, blurMat, blurSize);
            if (IsDebug)
                Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\QR_" + fileFrontName + "_2-模糊[平均模糊].jpg", blurMat);

            //二值化
            Mat thresholdMat = new Mat();
            Cv2.Threshold(blurMat, thresholdMat, 0, 255, ThresholdTypes.Otsu);
            if (IsDebug)
                Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\QR_" + fileFrontName + "_3-二值化.jpg", thresholdMat);

            ////开运算
            //Mat morphologyExMat = new Mat();
            //Mat element = Cv2.GetStructuringElement(MorphShapes.Cross, new OpenCvSharp.Size(10, 10));
            //Cv2.MorphologyEx(thresholdMat, morphologyExMat, MorphTypes.Open, element);
            //Cv2.ImWrite("4-开运算.jpg", morphologyExMat);

            //腐蚀一次，去掉细节，表格线等。这里去掉的是竖直的线
            Mat erodeMat = new Mat();
            Cv2.Erode(thresholdMat, erodeMat, elementBFErode);
            if (IsDebug)
                Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\QR_" + fileFrontName + "_5-腐蚀1.jpg", erodeMat);

            if (secondsTag)
            {
                Cv2.Erode(erodeMat, erodeMat, Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3)));
                if (IsDebug)
                    Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\QR_" + fileFrontName + "_5-腐蚀2.jpg", erodeMat);
            }

            //Cv2.Erode(erodeMat, erodeMat, elementBF);
            //Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\" + fileFrontName + "_5-腐蚀3.jpg", erodeMat);

            //膨胀一次，让轮廓突出
            Mat dilateMat = new Mat();
            Cv2.Dilate(erodeMat, dilateMat, elementBFDilate);
            if (IsDebug)
                Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\QR_" + fileFrontName + "_6-膨胀1.jpg", dilateMat);

            //再膨胀一次，让轮廓突出
            Cv2.Dilate(dilateMat, dilateMat, elementBFDilate);
            //Cv2.Dilate(dilateMat, dilateMat, elementBFDilate);
            if (IsDebug)
                Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\QR_" + fileFrontName + "_6-膨胀2.jpg", dilateMat);

            if (secondsTag)
            {
                Cv2.Dilate(dilateMat, dilateMat, Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(4, 4)));
                if (IsDebug)
                    Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\QR_" + fileFrontName + "_6-膨胀3.jpg", dilateMat);
            }
            //查找边缘
            Cv2.Canny(dilateMat, dilateMat, 75, 150, 7, true);
            if (IsDebug)
                Cv2.ImWrite("E:\\OenpCVImage\\" + dic + "\\QR_" + fileFrontName +"_7-查找边缘.jpg", dilateMat);
            CommonUtil.ClearMemory();
            return dilateMat;
            #endregion
        }

        /// <summary>
        /// 查找发票抬头标识区域的坐标
        /// </summary>
        /// <param name="img"></param>
        /// <returns></returns>
        public static List<RotatedRect> FindInvoiceTagRegion(Mat img)
        {
            #region
            List<RotatedRect> rects = new List<RotatedRect>();
            int w = img.Width;
            int h = img.Height;
            OpenCvSharp.Point point = new OpenCvSharp.Point(0, 0);
            HierarchyIndex[] hierarchy = null;
            OpenCvSharp.Point[][] contours = null;
            Cv2.FindContours(img, out contours, out hierarchy, RetrievalModes.List, ContourApproximationModes.ApproxNone, new OpenCvSharp.Point(0, 0));

            for (int i = 0; i < contours.Length; i++)
            {
                //找到最小矩形，该矩形可能有方向
                RotatedRect rect = Cv2.MinAreaRect(contours[i]);

                //计算高和宽
                int x = rect.BoundingRect().X;
                int y = rect.BoundingRect().Y;
                float w1 = rect.Size.Width;
                float h1 = rect.Size.Height;

                double matArea = w1 * h1;
                //筛选矩形
                if (matArea >= 40000 && matArea <= 550000)
                {
                    double rate = Math.Round((Math.Min(w1, h1) / Math.Max(w1, h1) * 1.0), 2);//长宽比例
                    if (0.28 <= rate && rate <= 0.35)//发票比例
                    {
                        //Console.WriteLine("长：" + w1 + "宽：" + h1);
                        //Console.WriteLine("面积：" + matArea);
                        //Console.WriteLine("合格比例：" + rate);
                        //Console.WriteLine("--------------分割线----------------");
                        //符合条件的rect添加到rects集合中
                        Console.WriteLine("x:"+rect.Center.X+",y:"+ rect.Center.Y);
                        rects.Add(rect);
                    }
                }
                //rects.Add(rect);
            }
            Console.WriteLine("-------------------------");
            return rects;
            #endregion
        }

        /// <summary>
        /// 查找发票二维码标识区域的坐标
        /// </summary>
        /// <param name="img"></param>
        /// <returns></returns>
        public static List<RotatedRect> FindQrCodeRegion(Mat img ,int dpi)
        {
            #region
            List<RotatedRect> rects = new List<RotatedRect>();
            int w = img.Width;
            int h = img.Height;
            OpenCvSharp.Point point = new OpenCvSharp.Point(0, 0);
            HierarchyIndex[] hierarchy = null;
            OpenCvSharp.Point[][] contours = null;
            Cv2.FindContours(img, out contours, out hierarchy, RetrievalModes.List, ContourApproximationModes.ApproxNone, new OpenCvSharp.Point(0, 0));
            List<int> MaxMin = OcrUtil.CompareScope(dpi);

            for (int i = 0; i < contours.Length; i++)
            {
                //找到最小矩形，该矩形可能有方向
                RotatedRect rect = Cv2.MinAreaRect(contours[i]);

                //计算高和宽
                int x = rect.BoundingRect().X;
                int y = rect.BoundingRect().Y;
                float w1 = rect.Size.Width;
                float h1 = rect.Size.Height;

                double matArea = w1 * h1;
                //Console.WriteLine("面积：" + matArea);
                //筛选矩形
                if (matArea >= MaxMin[0] && matArea < MaxMin[1])
                {
                    //Console.WriteLine("--------------分割线----------------");
                    //Console.WriteLine("面积：" + matArea);
                    double rate = Math.Round((Math.Min(w1, h1) / Math.Max(w1, h1) * 1.0), 2);//长宽比例
                    //Console.WriteLine("长：" + w1 + "宽：" + h1);
                    //Console.WriteLine("比例：" + rate);
                    if ((0.88 <= rate && rate <= 1.0))//发票比例
                    {
                        //Console.WriteLine("长：" + w1 + "宽：" + h1);
                        //Console.WriteLine("面积：" + matArea);
                        //Console.WriteLine("合格比例：" + rate);
                        //Console.WriteLine("--------------分割线----------------");
                        //符合条件的rect添加到rects集合中
                        rects.Add(rect);
                    }
                }
                //rects.Add(rect);
            }
            return rects;
            #endregion
        }

        /// <summary>
        /// 获取二维码区域
        /// </summary>
        /// <param name="x">x坐标点</param>
        /// <param name="y">y坐标点</param>
        /// <param name="bitmap">原图</param>
        /// <param name="w">width</param>
        /// <param name="h">height</param>
        /// <param name="filename">保存的路径</param>
        /// <returns>返回二维码区域的bitmap</returns>
        public static Bitmap SaveCutOutQrCode2Bitmap(int x, int y, Bitmap bitmap, float w, float h, string filename)
        {
            #region
            int offsetX = x;
            int offsetY = y;
            int width = (int)w;
            int height = (int)h;

            if (width>height) height = width;
            else width = height;

            Bitmap resultBitmap = new Bitmap(width, height);
            using (Graphics g = Graphics.FromImage(resultBitmap))
            {
                Rectangle resultRectangle = new Rectangle(0, 0, width, height);
                Rectangle sourceRectangle = new Rectangle(0 + offsetX, 0 + offsetY, width, height);
                g.DrawImage(bitmap, resultRectangle, sourceRectangle, GraphicsUnit.Pixel);
            }
            if (IsDebug || OutPutQrCodeTag)
                resultBitmap.Save("E:\\OenpCVImage\\QrCode_" + filename + ".jpg");
            return resultBitmap;
            #endregion
        }

        public static String ReadQrCode(List<RotatedRect> rects,Bitmap bitmap, String fileFrontName,Mat textImageSrc)
        {
            #region
            String QrCodeStr ="0";
            foreach (RotatedRect rect in rects)
            {
                int x = rect.BoundingRect().X;
                int y = rect.BoundingRect().Y;
                float w1 = rect.Size.Width;
                float h1 = rect.Size.Height;
                Scalar scalar = new Scalar(0, 255, 0);
                Point2f[] P = rect.Points();
                if (IsDebug)
                {
                    for (int j = 0; j <= 3; j++)//用绿线画出这些找到的轮廓
                        Cv2.Line(textImageSrc, P[j], P[(j + 1) % 4], scalar, 2);
                }

                Bitmap QrBitmap = SaveCutOutQrCode2Bitmap(x, y, bitmap, w1, h1, fileFrontName);
                //第一次识别 尝试识别原图
                QrCodeStr = NormalReadQrCode(QrBitmap);
                //第二次识别 对原图进行预处理
                if (QrCodeStr=="0")
                {
                    Mat qrMat = OcrUtil.BitmapToMat(QrBitmap);
                    Cv2.CvtColor(qrMat, qrMat, ColorConversionCodes.RGB2GRAY);
                    Mat thresholdMat = new Mat();
                    int count = 1;
                    int sizel = 1;
                    int sizer = 1;
                    int blockSize = 33;
                    do
                    {
                        //自适应阈值
                        Cv2.AdaptiveThreshold(qrMat, thresholdMat, 255, AdaptiveThresholdTypes.GaussianC, ThresholdTypes.Binary, blockSize, 0);
                        //开运算去除杂质
                        Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(sizel, sizer));
                        Cv2.MorphologyEx(thresholdMat, thresholdMat, MorphTypes.Open, element);
                        //保存处理的图像，然后获取成Bitmap格式
                        Cv2.ImWrite(@"C:\MssClientCache\QrCache\" + fileFrontName + "_" + count + ".jpg", thresholdMat);
                        Bitmap QrBitmapThresholdMat = new Bitmap(@"C:\MssClientCache\QrCache\" + fileFrontName + "_" + count + ".jpg");

                        QrCodeStr = NormalReadQrCode(QrBitmapThresholdMat);
                        if (QrCodeStr != "0")
                        {
                            QrBitmapThresholdMat.Dispose();
                            //File.Delete(@"C:\MssClientCache\QrCache\" + fileFrontName + "_" + count + ".jpg");
                            return QrCodeStr;
                        }

                        if (QrCodeStr == "0")
                        {
                            ZBar.ImageScanner imageScanner = new ZBar.ImageScanner();
                            imageScanner.SetConfiguration(ZBar.SymbolType.QRCODE, ZBar.Config.Enable, 1);
                            List<Symbol> zbarQrcode = imageScanner.Scan(QrBitmapThresholdMat);
                            if (zbarQrcode.Count != 0)
                            {
                                QrBitmapThresholdMat.Dispose();
                                //File.Delete(@"C:\MssClientCache\QrCache\" + fileFrontName + "_" + count + ".jpg");
                                Console.WriteLine("zbar二维码识别：" + zbarQrcode[0].Data);
                                QrCodeStr = zbarQrcode[0].Data;
                                return QrCodeStr;
                            }
                        }
                        QrBitmapThresholdMat.Dispose();
                        sizer++;
                        sizel++;
                        ++count;
                        blockSize += 2;
                        CommonUtil.ClearMemory();
                    } while (sizer<=4);
                }
                QrBitmap.Dispose();
                if (IsDebug) ;
                    //textImageSrc.SaveImage("E:\\OenpCVImage\\" + fileFrontName + "-二维码标识图.jpg");
            }
            return QrCodeStr;
            #endregion
        }

        public static String NormalReadQrCode(Bitmap QrBitmap)
        {
            #region
            String QrCodeStr = "0";
            LuminanceSource source = new BitmapLuminanceSource((QrBitmap));
            var binarizer = new ZXing.Common.HybridBinarizer(source);
            var binBitmap = new BinaryBitmap(binarizer);
            var hints = new Dictionary<DecodeHintType, object>();
            hints.Add(DecodeHintType.TRY_HARDER, true);
            var hints2 = new Dictionary<DecodeHintType, object>(hints);
            hints2.Add(DecodeHintType.PURE_BARCODE, true);
            hints.Add(DecodeHintType.CHARACTER_SET, "utf-8");
            var result = new MultiFormatReader().decode(binBitmap, hints);
            if (result != null)
            {
                QrCodeStr = result.Text;
                Console.WriteLine("ZXing二维码识别1：" + QrCodeStr);
                return QrCodeStr;
            }
            return QrCodeStr;
            #endregion
        }

    }
}
